package com.yancloud.android.reflection.get;


import android.os.Handler;
import android.util.Log;
import android.widget.Toast;

import com.google.gson.Gson;
import com.koushikdutta.async.AsyncServer;
import com.koushikdutta.async.ByteBufferList;
import com.koushikdutta.async.DataEmitter;
import com.koushikdutta.async.callback.CompletedCallback;
import com.koushikdutta.async.callback.DataCallback;
import com.koushikdutta.async.http.AsyncHttpClient;
import com.koushikdutta.async.http.AsyncHttpGet;
import com.koushikdutta.async.http.AsyncHttpPost;
import com.koushikdutta.async.http.AsyncHttpResponse;
import com.koushikdutta.async.http.Multimap;
import com.koushikdutta.async.http.body.AsyncHttpRequestBody;
import com.koushikdutta.async.http.body.MultipartFormDataBody;
import com.koushikdutta.async.http.body.Part;
import com.koushikdutta.async.http.callback.HttpConnectCallback;
import com.koushikdutta.async.http.server.AsyncHttpServerRequest;
import com.koushikdutta.async.http.server.AsyncHttpServerResponse;
import com.yancloud.android.manager.URLRegx;

import java.io.ByteArrayOutputStream;
import java.io.DataOutputStream;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.PrintStream;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;

import ias.deepsearch.com.helper.service.DaemonService;
import ias.deepsearch.com.helper.util.ShellUtils;
import ias.deepsearch.com.helper.util.normal.FileUtil;
import retrofit.http.GET;
import retrofit.http.POST;


public class FileHelper {
    static{
                new Thread(new Runnable() {
                    @Override
                    public void run() {
//                        try {
//                            Thread.sleep(500);
//                        } catch (InterruptedException e) {
//                            e.printStackTrace();
//                        }
//                        String url ="http://127.0.0.1:6161/";
//                        AsyncHttpPost post = new AsyncHttpPost("http://127.0.0.1:6161/upload?getMessage={\"method\":\"create\",\"arg\":\"/sdcard/apiminier/empty.dex\"}");
//                        MultipartFormDataBody body = new MultipartFormDataBody();
//                        File temp = null;
//                        try {
//                            temp = File.createTempFile("abc","def");
//                            temp.createNewFile();
//                        } catch (IOException e) {
//                            e.printStackTrace();
//                        }
//                        body.addFilePart("file",temp);
//                        body.addStringPart("foo", "bar");
//                        post.setBody(body);
//                        AsyncHttpClient.getDefaultInstance().execute(post, new HttpConnectCallback() {
//                            @Override
//                            public void onConnectCompleted(Exception ex, AsyncHttpResponse response) {
//                                if (ex != null) {
//                                    ex.printStackTrace();
//                                    return;
//                                }
//
//                                System.out.println("[Init Server] done!" + response.toString());
//							}
//                        });
						try {
							Thread.sleep(1000);

							DaemonService.post(new Runnable() {
								@Override
								public void run() {
									Toast.makeText(DaemonService.instance, "后台服务开启成功", Toast.LENGTH_SHORT).show();
								}
							});
						} catch (InterruptedException e) {
							e.printStackTrace();
						}
					}
        }).start();

    }

	public static String handle(GetMessage message) {
		try {
			Method m  = FileHelper.class.getDeclaredMethod(message.method,String.class);
			return (String)m.invoke(null,message.arg);
		} catch (Throwable t) {
			t.printStackTrace();
			return "Exception:" + t.getMessage();
		}
	}

	public static String execCommand(String command){
		try {
			ShellUtils.CommandResult result = ShellUtils.execCommand(command, true);
			return new Gson().toJson(result);
		}catch(Exception e){
			ByteArrayOutputStream bo = new ByteArrayOutputStream();
			e.printStackTrace(new PrintStream(bo));
			return bo.toString();
		}
	}

	public static String rootCommand(String command) {
		Process process = null;
		DataOutputStream os = null;
		try {
			process = Runtime.getRuntime().exec("su");
			os = new DataOutputStream(process.getOutputStream());
			os.writeBytes(command + "\n");
			os.writeBytes("exit\n");
			os.flush();
			process.waitFor();
		} catch (Exception e) {
			return "failed";
		} finally {
			try {
				if (os != null) {
					os.close();
				}
				process.destroy();
			} catch (Exception e) {
			}
		}
		return "success";
	}
	static class NameAndSize{
		String name;
		long size;
	}
	public static String lsDirWithSize(String args){
		File[] files = new File(args).listFiles();
		List<NameAndSize> ret = new ArrayList<>();
		for (File f:files){
			NameAndSize item = new NameAndSize();
			item.name = f.getName();
			item.size = f.length();
			ret.add(item);
		}
		return new Gson().toJson(ret);
	}

	public static String calculatePkgUsage(String pkgName) {
		long dataSize = 0;
		File dir = new File("/data/data/");
		for (File f : dir.listFiles()) {
			if (f.isDirectory() && f.getName().startsWith(pkgName)) {
				dataSize = FileUtil.getDirSize(f);
			}
		}
		dir = new File("/sdcard/Android/data/");

		for (File f : dir.listFiles()) {
			if (f.isDirectory() && f.getName().startsWith(pkgName)) {
				dataSize = FileUtil.getDirSize(f);
			}
		}
		Log.d("FileHelper","calculatePkgUsage:"+dir.listFiles().length);
		return dataSize + "," + dataSize;
	}
	public static String lsDir(String args){
		ByteArrayOutputStream bo = new ByteArrayOutputStream();
		PrintStream ps = new PrintStream(bo);
		try{
		String[] f = new File(args).list();
		for (String fileName:f)
			ps.println(fileName);
		}catch(Throwable t){
			t.printStackTrace(ps);
		}
		return bo.toString();
	}
	public static String rmFile(String args){
		ByteArrayOutputStream bo = new ByteArrayOutputStream();
		PrintStream ps = new PrintStream(bo);
		try{
			new File(args).delete();
			ps.println("success");
		}catch(Throwable t){
			t.printStackTrace(ps);
		}
		return bo.toString();
	}
	@URLRegx("/filehelper")
	public static void onRequest(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {
			Multimap query = request.getQuery();
			String getMessage = query.getString("getMessage");
			GetMessage message = new Gson().fromJson(getMessage, GetMessage.class);
			String result = handle(message);
			response.send(result);
	}
	@URLRegx("/fileprovider")
	public static void fileProvider(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {
		Multimap query = request.getQuery();
		String getMessage = query.getString("getMessage");
		GetMessage message = new Gson().fromJson(getMessage, GetMessage.class);
		File toSend = new File(message.arg);
		Log.d("FileHelper","fileProvider:"+message.arg+" is exist:"+toSend.exists()+" len:"+toSend.length());
		if (toSend.length()>0)
			response.sendFile(toSend);
		else
			response.send("File Not Exists");
	}
	static class UploadInfo {

	}
	private static byte[] str2Byte(String str) {
		byte[] ret = new byte[str.length() / 2];
		for (int i = 0; i < str.length() / 2; i++) {
			int val = (char2Int(str.charAt(i * 2)) << 4) + (char2Int(str.charAt(i * 2 + 1)));
			ret[i] = (byte) (val & 0xff);
		}
		// TODO Auto-generated method stub
		return ret;
	}
	private static int char2Int(char c) {
		int ret = c;
		if (c >= 'a' && c <= 'f') {
			ret = '0' + 10 + c - 'a';
		}
		ret = ret - '0';
		if (ret >= 0 && ret < 16) {
			return ret;
		} else
			throw new IllegalArgumentException("the input should be 0-9 and a-f, but received " + c);
	}

	@URLRegx("/upload2")
	@GET
	public static void receiveFileGet(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {
    	Log.d("[FileHelper]","uploadFile2");
    	int len =  -1;
    	try {
			Multimap query = request.getQuery();
			boolean isAppend = Boolean.valueOf(query.getString("isAppend"));
			String dest = query.getString("dest");
			String content = query.getString("content");
			byte[] bytes = str2Byte(content);
			FileOutputStream fout = new FileOutputStream(dest, isAppend);
			len = bytes.length;
			fout.write(bytes);
			fout.close();
		}catch(Exception e){
    		e.printStackTrace();
		}
		Log.d("[FileHelper]","uploadFile, len:"+len);
		response.send("Receive "+len);
		request.close();
	}

	@URLRegx("/upload")
	@POST
	public static void receiveFile(AsyncHttpServerRequest request, AsyncHttpServerResponse response) {
		Log.d("FileHelper", "receiveFile start!");
		Multimap query = request.getQuery();
		String getMessage = query.getString("getMessage");
		GetMessage message = new Gson().fromJson(getMessage, GetMessage.class);
		AsyncHttpRequestBody bb = request.getBody();
	//	request.setDataCallback();
	//	MultipartFormDataBody body = (MultipartFormDataBody)request.getBody();

		final MultipartCb cb = new MultipartCb(response,message.arg,message.method.equals("append"));
		//request.setMultipartCallback(cb);
		request.setEndCallback(cb);
		request.setDataCallback(new DataCallback() {
			@Override
			public void onDataAvailable(DataEmitter emitter, ByteBufferList bb) {
				try {
					cb.size += bb.remaining();
					if (cb.size>cb.delta){
						cb.delta*=2;
						Log.d("FileHelper",cb.byteToDisplay(cb.size) + "...");
					}
					cb.fout.write(bb.getAllByteArray());
					bb.recycle();

				} catch (Exception e) {
					e.printStackTrace();
				}

			}
		});

	}
	private static class MultipartCb implements MultipartFormDataBody.MultipartCallback, CompletedCallback{
		AsyncHttpServerResponse response;
		FileOutputStream fout;
		int size;
		int delta = 4*1024;
		MultipartCb(AsyncHttpServerResponse r,String path,boolean isAppend){
			response = r;
			size = 0;
			try {
				fout = new FileOutputStream(path,isAppend);
			} catch (FileNotFoundException e) {
				ByteArrayOutputStream bo = new ByteArrayOutputStream();
				e.printStackTrace(new PrintStream(bo));
				response.send(bo.toString());
			}
		}
		private String byteToDisplay(int total) {
			String str = "byte";
			if (total > 1024) {
				total /= 1024;
				str = "kb";
			}
			if (total > 1024) {
				total /= 1024;
				str = "mb";
			}
			return total + str;
		}
		@Override
		public void onPart(Part part) {
			Log.d("FileHelper","Multipartcb.onPart:"+part.length());
			if (part.isFile()) {

			}else{

			}
		}

		@Override
		public void onCompleted(Exception ex) {
			try {
				fout.close();
			} catch (IOException e) {
				e.printStackTrace();
			}
			response.send("[MultipartCb] done! Received:"+size);
		}
	}
}
